import * as THREE from '../build/three.module.js'
import {
    UIPanel,
    UIRow,
    UIInput,
    UIButton,
    UIColor,
    UICheckbox,
    UIInteger,
    UITextArea,
    UIText,
    UINumber
} from './libs/ui.js';
import {UIBoolean} from './libs/ui.three.js';
import {
    SetPositionCommand,
    SetRotationCommand,
    SetScaleCommand,
    SetUuidCommand,
    SetValueCommand
} from "./commands/Commands.js";

function PropertyObject(editor)
{
    var signals = editor.signals;

    var objectPanel = new UIPanel();
    objectPanel.setDisplay('none');

    var objectTypeRow = new UIRow();
    var objectType = new UIText();

    objectTypeRow.add(new UIText('类型').setWidth('90px'));
    objectTypeRow.add(objectType);

    objectPanel.add(objectTypeRow);

    // uuid

    var objectUUIDRow = new UIRow();
    var objectUUID = new UIInput().setWidth('102px').setFontSize('12px').setDisabled(true);
    var objectUUIDRenew = new UIButton('生成').setMarginLeft('7px').onClick(function () {
        objectUUID.setValue(THREE.MathUtils.generateUUID());
        editor.execute(new SetUuidCommand(editor, editor.selected, objectUUID.getValue()));
    });

    objectUUIDRow.add(new UIText('uuid').setWidth('90px'));
    objectUUIDRow.add(objectUUID);
    objectUUIDRow.add(objectUUIDRenew);

    objectPanel.add(objectUUIDRow);

    // name

    var objectNameRow = new UIRow();
    var objectName = new UIInput().setWidth('150px').setFontSize('12px').onChange(function () {
        editor.execute(new SetValueCommand(editor, editor.selected, 'name', objectName.getValue()));
    });

    objectNameRow.add(new UIText('名称').setWidth('90px'));
    objectNameRow.add(objectName);

    objectPanel.add(objectNameRow);

    var objectPositionRow = new UIRow();
    var objectPositionX = new UINumber().setPrecision(3).setWidth('50px').onChange(update);
    var objectPositionY = new UINumber().setPrecision(3).setWidth('50px').onChange(update);
    var objectPositionZ = new UINumber().setPrecision(3).setWidth('50px').onChange(update);

    objectPositionRow.add(new UIText('位置').setWidth('90px'));
    objectPositionRow.add(objectPositionX, objectPositionY, objectPositionZ);

    objectPanel.add(objectPositionRow);

    var objectRotationRow = new UIRow();
    var objectRotationX = new UINumber().setStep(10).setNudge(0.1).setUnit('°').setWidth('50px').onChange(update);
    var objectRotationY = new UINumber().setStep(10).setNudge(0.1).setUnit('°').setWidth('50px').onChange(update);
    var objectRotationZ = new UINumber().setStep(10).setNudge(0.1).setUnit('°').setWidth('50px').onChange(update);

    objectRotationRow.add(new UIText('旋转').setWidth('90px'));
    objectRotationRow.add(objectRotationX, objectRotationY, objectRotationZ);

    objectPanel.add(objectRotationRow);

    var objectScaleRow = new UIRow();
    var objectScaleX = new UINumber(1).setPrecision(3).setWidth('50px').onChange(update);
    var objectScaleY = new UINumber(1).setPrecision(3).setWidth('50px').onChange(update);
    var objectScaleZ = new UINumber(1).setPrecision(3).setWidth('50px').onChange(update);

    objectScaleRow.add(new UIText('缩放').setWidth('90px'));
    objectScaleRow.add(objectScaleX, objectScaleY, objectScaleZ);

    objectPanel.add(objectScaleRow);

    // fov

    var objectFovRow = new UIRow();
    var objectFov = new UINumber().onChange(update);

    objectFovRow.add(new UIText('视角').setWidth('90px'));
    objectFovRow.add(objectFov);

    objectPanel.add(objectFovRow);

    // left

    var objectLeftRow = new UIRow();
    var objectLeft = new UINumber().onChange(update);

    objectLeftRow.add(new UIText('左').setWidth('90px'));
    objectLeftRow.add(objectLeft);

    objectPanel.add(objectLeftRow);

    // right

    var objectRightRow = new UIRow();
    var objectRight = new UINumber().onChange(update);

    objectRightRow.add(new UIText('右').setWidth('90px'));
    objectRightRow.add(objectRight);

    objectPanel.add(objectRightRow);

    // top

    var objectTopRow = new UIRow();
    var objectTop = new UINumber().onChange(update);

    objectTopRow.add(new UIText('上').setWidth('90px'));
    objectTopRow.add(objectTop);

    objectPanel.add(objectTopRow);

    // bottom

    var objectBottomRow = new UIRow();
    var objectBottom = new UINumber().onChange(update);

    objectBottomRow.add(new UIText('下').setWidth('90px'));
    objectBottomRow.add(objectBottom);

    objectPanel.add(objectBottomRow);

    // near

    var objectNearRow = new UIRow();
    var objectNear = new UINumber().onChange(update);

    objectNearRow.add(new UIText('近点').setWidth('90px'));
    objectNearRow.add(objectNear);

    objectPanel.add(objectNearRow);

    // far

    var objectFarRow = new UIRow();
    var objectFar = new UINumber().onChange(update);

    objectFarRow.add(new UIText('远点').setWidth('90px'));
    objectFarRow.add(objectFar);

    objectPanel.add(objectFarRow);

    // intensity

    var objectIntensityRow = new UIRow();
    var objectIntensity = new UINumber().onChange(update);

    objectIntensityRow.add(new UIText('强度').setWidth('90px'));
    objectIntensityRow.add(objectIntensity);

    objectPanel.add(objectIntensityRow);

    // color

    var objectColorRow = new UIRow();
    var objectColor = new UIColor().onInput(update);

    objectColorRow.add(new UIText('颜色').setWidth('90px'));
    objectColorRow.add(objectColor);

    objectPanel.add(objectColorRow);

    // ground color

    var objectGroundColorRow = new UIRow();
    var objectGroundColor = new UIColor().onInput(update);

    objectGroundColorRow.add(new UIText('基色')).setWidth('90px');
    objectGroundColorRow.add(objectGroundColor);

    objectPanel.add(objectGroundColorRow);

    // distance

    var objectDistanceRow = new UIRow();
    var objectDistance = new UINumber().setRange(0, Infinity).onChange(update);

    objectDistanceRow.add(new UIText('距离').setWidth('90px'));
    objectDistanceRow.add(objectDistance);

    objectPanel.add(objectDistanceRow);

    // angle

    var objectAngleRow = new UIRow();
    var objectAngle = new UINumber().setPrecision(3).setRange(0, Math.PI / 2).onChange(update);

    objectAngleRow.add(new UIText('角度').setWidth('90px'));
    objectAngleRow.add(objectAngle);

    objectPanel.add(objectAngleRow);

    // penumbra

    var objectPenumbraRow = new UIRow();
    var objectPenumbra = new UINumber().setRange(0, 1).onChange(update);

    objectPenumbraRow.add(new UIText('边缘').setWidth('90px'));
    objectPenumbraRow.add(objectPenumbra);

    objectPanel.add(objectPenumbraRow);

    // decay

    var objectDecayRow = new UIRow();
    var objectDecay = new UINumber().setRange(0, Infinity).onChange(update);

    objectDecayRow.add(new UIText('衰减').setWidth('90px'));
    objectDecayRow.add(objectDecay);

    objectPanel.add(objectDecayRow);

    // shadow

    var objectShadowRow = new UIRow();

    objectShadowRow.add(new UIText('阴影').setWidth('90px'));

    var objectCastShadow = new UIBoolean(false, '产生').onChange(update);
    objectShadowRow.add(objectCastShadow);

    var objectReceiveShadow = new UIBoolean(false, '接收').onChange(update);
    objectShadowRow.add(objectReceiveShadow);

    objectPanel.add(objectShadowRow);

    // shadow bias

    var objectShadowBiasRow = new UIRow();

    objectShadowBiasRow.add(new UIText('阴影偏移').setWidth('90px'));

    var objectShadowBias = new UINumber(0).setPrecision(5).setStep(0.0001).setNudge(0.00001).onChange(update);
    objectShadowBiasRow.add(objectShadowBias);

    objectPanel.add(objectShadowBiasRow);

    // shadow normal offset

    var objectShadowNormalBiasRow = new UIRow();

    objectShadowNormalBiasRow.add(new UIText('阴影法线偏移').setWidth('90px'));

    var objectShadowNormalBias = new UINumber(0).onChange(update);
    objectShadowNormalBiasRow.add(objectShadowNormalBias);

    objectPanel.add(objectShadowNormalBiasRow);

    // shadow radius

    var objectShadowRadiusRow = new UIRow();

    objectShadowRadiusRow.add(new UIText('阴影半径').setWidth('90px'));

    var objectShadowRadius = new UINumber(1).onChange(update);
    objectShadowRadiusRow.add(objectShadowRadius);

    objectPanel.add(objectShadowRadiusRow);

    // visible

    var objectVisibleRow = new UIRow();
    var objectVisible = new UICheckbox().onChange(update);

    objectVisibleRow.add(new UIText('可见性').setWidth('90px'));
    objectVisibleRow.add(objectVisible);

    objectPanel.add(objectVisibleRow);

    // frustumCulled

    var objectFrustumCulledRow = new UIRow();
    var objectFrustumCulled = new UICheckbox().onChange(update);

    objectFrustumCulledRow.add(new UIText('视锥体裁剪').setWidth('90px'));
    objectFrustumCulledRow.add(objectFrustumCulled);

    objectPanel.add(objectFrustumCulledRow);

    // renderOrder

    var objectRenderOrderRow = new UIRow();
    var objectRenderOrder = new UIInteger().setWidth('50px').onChange(update);

    objectRenderOrderRow.add(new UIText('渲染次序').setWidth('90px'));
    objectRenderOrderRow.add(objectRenderOrder);

    objectPanel.add(objectRenderOrderRow);


    function update() {
        var object = editor.selected;
        if (object !== null) {
            var newPosition = new THREE.Vector3(objectPositionX.getValue(), objectPositionY.getValue(), objectPositionZ.getValue());
            if (object.position.distanceTo(newPosition) >= 0.01) {
                editor.execute(new SetPositionCommand(editor, object, newPosition));
            }

            var newRotation = new THREE.Euler(objectRotationX.getValue() * THREE.MathUtils.DEG2RAD, objectRotationY.getValue() * THREE.MathUtils.DEG2RAD, objectRotationZ.getValue() * THREE.MathUtils.DEG2RAD);
            if (object.rotation.toVector3().distanceTo(newRotation.toVector3()) >= 0.01) {
                editor.execute(new SetRotationCommand(editor, object, newRotation));
            }

            var newScale = new THREE.Vector3(objectScaleX.getValue(), objectScaleY.getValue(), objectScaleZ.getValue());
            if (object.scale.distanceTo(newScale) >= 0.01) {
                editor.execute(new SetScaleCommand(editor, object, newScale));
            }

            if (object.fov !== undefined && Math.abs(object.fov - objectFov.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'fov', objectFov.getValue()));
                object.updateProjectionMatrix();
            }

            if (object.left !== undefined && Math.abs(object.left - objectLeft.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'left', objectLeft.getValue()));
                object.updateProjectionMatrix();
            }

            if (object.right !== undefined && Math.abs(object.right - objectRight.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'right', objectRight.getValue()));
                object.updateProjectionMatrix();
            }

            if (object.top !== undefined && Math.abs(object.top - objectTop.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'top', objectTop.getValue()));
                object.updateProjectionMatrix();
            }

            if (object.bottom !== undefined && Math.abs(object.bottom - objectBottom.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'bottom', objectBottom.getValue()));
                object.updateProjectionMatrix();
            }

            if (object.near !== undefined && Math.abs(object.near - objectNear.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'near', objectNear.getValue()));
                if (object.isOrthographicCamera) {
                    object.updateProjectionMatrix();
                }
            }

            if (object.far !== undefined && Math.abs(object.far - objectFar.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'far', objectFar.getValue()));
                if (object.isOrthographicCamera) {
                    object.updateProjectionMatrix();
                }
            }

            if (object.intensity !== undefined && Math.abs(object.intensity - objectIntensity.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'intensity', objectIntensity.getValue()));
            }

            if (object.color !== undefined && object.color.getHex() !== objectColor.getHexValue()) {
                editor.execute(new SetColorCommand(editor, object, 'color', objectColor.getHexValue()));
            }

            if (object.groundColor !== undefined && object.groundColor.getHex() !== objectGroundColor.getHexValue()) {
                editor.execute(new SetColorCommand(editor, object, 'groundColor', objectGroundColor.getHexValue()));
            }

            if (object.distance !== undefined && Math.abs(object.distance - objectDistance.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'distance', objectDistance.getValue()));
            }

            if (object.angle !== undefined && Math.abs(object.angle - objectAngle.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'angle', objectAngle.getValue()));
            }

            if (object.penumbra !== undefined && Math.abs(object.penumbra - objectPenumbra.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'penumbra', objectPenumbra.getValue()));
            }

            if (object.decay !== undefined && Math.abs(object.decay - objectDecay.getValue()) >= 0.01) {
                editor.execute(new SetValueCommand(editor, object, 'decay', objectDecay.getValue()));
            }

            if (object.visible !== objectVisible.getValue()) {
                editor.execute(new SetValueCommand(editor, object, 'visible', objectVisible.getValue()));
            }

            if (object.frustumCulled !== objectFrustumCulled.getValue()) {
                editor.execute(new SetValueCommand(editor, object, 'frustumCulled', objectFrustumCulled.getValue()));
            }

            if (object.renderOrder !== objectRenderOrder.getValue()) {
                editor.execute(new SetValueCommand(editor, object, 'renderOrder', objectRenderOrder.getValue()));
            }

            if (object.castShadow !== undefined && object.castShadow !== objectCastShadow.getValue()) {
                editor.execute(new SetValueCommand(editor, object, 'castShadow', objectCastShadow.getValue()));
            }

            if (object.receiveShadow !== objectReceiveShadow.getValue()) {
                if (object.material !== undefined) object.material.needsUpdate = true;
                editor.execute(new SetValueCommand(editor, object, 'receiveShadow', objectReceiveShadow.getValue()));
            }

            if (object.shadow !== undefined) {
                if (object.shadow.bias !== objectShadowBias.getValue()) {
                    editor.execute(new SetValueCommand(editor, object.shadow, 'bias', objectShadowBias.getValue()));
                }
                if (object.shadow.normalBias !== objectShadowNormalBias.getValue()) {
                    editor.execute(new SetValueCommand(editor, object.shadow, 'normalBias', objectShadowNormalBias.getValue()));
                }
                if (object.shadow.radius !== objectShadowRadius.getValue()) {
                    editor.execute(new SetValueCommand(editor, object.shadow, 'radius', objectShadowRadius.getValue()));
                }
            }
        }
    }

    function updateRows(object) {
        var properties = {
            'fov': objectFovRow,
            'left': objectLeftRow,
            'right': objectRightRow,
            'top': objectTopRow,
            'bottom': objectBottomRow,
            'near': objectNearRow,
            'far': objectFarRow,
            'intensity': objectIntensityRow,
            'color': objectColorRow,
            'groundColor': objectGroundColorRow,
            'distance': objectDistanceRow,
            'angle': objectAngleRow,
            'penumbra': objectPenumbraRow,
            'decay': objectDecayRow,
            'castShadow': objectShadowRow,
            'receiveShadow': objectReceiveShadow,
            'shadow': [objectShadowBiasRow, objectShadowNormalBiasRow, objectShadowRadiusRow]
        };

        for (var property in properties) {
            var uiElement = properties[property];
            if (Array.isArray(uiElement) === true) {
                for (var i = 0; i < uiElement.length; i++) {
                    uiElement[i].setDisplay(object[property] !== undefined ? '' : 'none');
                }
            } else {
                uiElement.setDisplay(object[property] !== undefined ? '' : 'none');
            }
        }

        //

        if (object.isLight) {
            objectReceiveShadow.setDisplay('none');
        }
        if (object.isAmbientLight || object.isHemisphereLight) {
            objectShadowRow.setDisplay('none');
        }
    }

    function updateTransformRows(object) {
        if (object.isLight ||
            object.isObject3D) {
            objectRotationRow.setDisplay('none');
            objectScaleRow.setDisplay('none');
        } else {
            objectRotationRow.setDisplay('');
            objectScaleRow.setDisplay('');
        }
    }

    function updateUI(object) {

        objectType.setValue(object.type);

        objectUUID.setValue(object.uuid);
        objectName.setValue(object.name);

        objectPositionX.setValue(object.position.x);
        objectPositionY.setValue(object.position.y);
        objectPositionZ.setValue(object.position.z);

        objectRotationX.setValue(object.rotation.x * THREE.MathUtils.RAD2DEG);
        objectRotationY.setValue(object.rotation.y * THREE.MathUtils.RAD2DEG);
        objectRotationZ.setValue(object.rotation.z * THREE.MathUtils.RAD2DEG);

        objectScaleX.setValue(object.scale.x);
        objectScaleY.setValue(object.scale.y);
        objectScaleZ.setValue(object.scale.z);

        if (object.fov !== undefined) {
            objectFov.setValue(object.fov);
        }

        if (object.left !== undefined) {
            objectLeft.setValue(object.left);
        }

        if (object.right !== undefined) {
            objectRight.setValue(object.right);
        }

        if (object.top !== undefined) {
            objectTop.setValue(object.top);
        }

        if (object.bottom !== undefined) {
            objectBottom.setValue(object.bottom);
        }

        if (object.near !== undefined) {
            objectNear.setValue(object.near);
        }

        if (object.far !== undefined) {
            objectFar.setValue(object.far);
        }

        if (object.intensity !== undefined) {
            objectIntensity.setValue(object.intensity);
        }

        if (object.color !== undefined) {
            objectColor.setHexValue(object.color.getHexString());
        }

        if (object.groundColor !== undefined) {
            objectGroundColor.setHexValue(object.groundColor.getHexString());
        }

        if (object.distance !== undefined) {
            objectDistance.setValue(object.distance);
        }

        if (object.angle !== undefined) {
            objectAngle.setValue(object.angle);
        }

        if (object.penumbra !== undefined) {
            objectPenumbra.setValue(object.penumbra);
        }

        if (object.decay !== undefined) {
            objectDecay.setValue(object.decay);
        }

        if (object.castShadow !== undefined) {
            objectCastShadow.setValue(object.castShadow);
        }

        if (object.receiveShadow !== undefined) {
            objectReceiveShadow.setValue(object.receiveShadow);
        }

        if (object.shadow !== undefined) {
            objectShadowBias.setValue(object.shadow.bias);
            objectShadowNormalBias.setValue(object.shadow.normalBias);
            objectShadowRadius.setValue(object.shadow.radius);
        }

        objectVisible.setValue(object.visible);
        objectFrustumCulled.setValue(object.frustumCulled);
        objectRenderOrder.setValue(object.renderOrder);

        updateTransformRows(object);
    }

    // signals

    signals.objectSelected.add(function(object){
        if (object!==null){
            objectPanel.setDisplay('block');
            updateRows(object);
            updateUI(object);
        }
        else{
            objectPanel.setDisplay('none');
        }
    })

    signals.objectChanged.add(function(object){
        if (object!==editor.selected)return;
        updateUI(object);
    })

    signals.refreshObject3DUI.add(function(object){
        if (object!==editor.selected)return;
        updateUI(object);
    })

    return objectPanel;
}

export {PropertyObject}